﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using RaytracerLib.MathLib;
using RaytracerLib.Samplers;
using System.Collections.Concurrent;
using NLog;
using RaytracerLib.Postprocessing.LightCorrector;
using TomanuExtensions;
using RaytracerLib.Rays;
using System.Threading;
using RaytracerLib.Resamplers;
using YAXLib;
using RaytracerLib.Layers;

namespace RaytracerLib.Renderers
{
    public class SamplesVisualizerRenderer : Renderer
    {
        [YAXNode]
        public int Scale = 9;

        public bool SuppressLog = false;

        private Renderer m_renderer;
        private List<Vector2> m_samples = new List<Vector2>();

        public override void Render()
        {
            Scene scene = Scene.DeepClone();
            scene.RenderOptions.Renderer = Renderer.Create(RendererType.Backward);
            scene.ActiveCamera.Film.Width = Film.Width / Scale + 1;
            scene.ActiveCamera.Film.Height = Film.Height / Scale + 1;

            Film.Sampler = Sampler.Create(SamplerType.Grid);

            m_renderer = scene.CreateRenderer();
            m_renderer.ShouldStop += () => DoShouldStop();
            m_renderer.PrepareToRender();
            
            base.Render();

            if (!SuppressLog)
            {
                double d = LowDiscrepancyMath.StarDiscrepancy(m_samples,
                    m_renderer.Film.Width, m_renderer.Film.Height);
                Loggers.Raytracer.Info("Discrepancy: {0}", d);

                int samples = 0;
                foreach (var p in Canvas.PostprocessedArray.Pixels())
                {
                    if (Canvas.PostprocessedArray[p.X, p.Y] != ColorFloat.Black)
                        samples++;
                }

                Loggers.Raytracer.Info("Fill ratio: {0}, Doubles: {1}%", 
                    1.0 * samples / (Film.Width * Film.Height), 100 * (1.0 * m_samples.Count - samples) / m_samples.Count);
            }
        }

        protected override void RenderTile(Tile a_tile)
        {
            Rectangle rect = new Rectangle(0, 0, a_tile.Rect.Width / Scale + 1, a_tile.Rect.Height / Scale + 1);

            foreach (Vector2 sample in m_renderer.Film.Sampler.GetSamples(rect))
            {
                Vector2 s = sample * Scale;

                if (s.X >= Film.Width)
                    continue;
                if (s.Y >= Film.Height)
                    continue;

                Film.Resampler.SetRayColor(s, ColorFloat.White);

                if (DoShouldStop())
                    break;

                m_samples.Add(sample);
            }

            TileRendered(a_tile);
        }

        protected override void PrepareTiles(Rectangle a_rect)
        {
            m_tiles_yx = new Tile[1, 1];
            m_tiles_yx[0, 0] = new Tile()
            {
                AffectedRect = a_rect,
                Rect = a_rect,
                X = 0,
                Y = 0
            };
        }

        public override RendererType RendererType
        {
            get
            {
                return RendererType.SamplesVisualizer;
            }
        }
    }
}